from logging import log, debug, info, warning, error, critical, exception
import logging
from math import floor
logging.basicConfig(level = logging.DEBUG)

# epsilon for floating point
E = 0.0000001

JOB_MOBILITY = 0.125

HOUSING_GROWTH = 0.0005
PEOPLE_PER_HOUSE = 1.0
FOOD_GROWTH = 0.0005
METAL_GROWTH = 0.0005
RESEARCH_GROWTH = 0.0005
SHIP_GROWTH = 0.0005

FOOD_CONSUMPTION = 0.00005 # per person, per tick
STARVATION_DEATH_RATE = 0.005


# 1000 ticks is one year, this r corresponds to a population growth rate of
# 4.5%, which seems reasonable for a very high technology level on untapped
# land.  This rate will in practice be modified by unnatural deaths and
# "bonus" population growth for things like additional spending on housing
POPULATION_GROWTH = 0.000045

# Actual growth rate is multiplied by:
# habitability ** POP_GROWTH_HAB_MODIFIER
# so for values less than one, this will lessen the effect somewhat
# in comparison to if it was linear
#
# Also, the minimum habitability value for this calculation
# is the DOME_CUTOFF below
POPULATION_GROWTH_HAB_MODIFIER = 1.0 / 3.0
# For this value, population growth rate will be .7368 times the above constant
# at DOME_CUTOFF of .4


# Similar to above, still has a dome cutoff
FOOD_GROWTH_HAB_MODIFIER = 0.7


# This constant is similar to the above, but with metal, and there is no
# dome cutoff
METAL_GROWTH_MET_MODIFIER = 1.2

# Same as above, no dome cutoff
HOUSING_GROWTH_HAB_MODIFIER = 1.0


# This is similar to the above, but:
# STARVATION_DEATH_RATE = base * 1.0 / hab ** STARVATION_HAB_MODIFIER
STARVATION_HAB_MODIFIER = 0.5


# adds a bonus growth rate of  min((MULTIPLIER * raw) ** EXPONENT, MAX)
# where raw is the fraction surplus_houses / total_houses
HOUSING_POP_BONUS_MULTIPLIER = 0.5
HOUSING_POP_BONUS_EXPONENT = 2.0
HOUSING_POP_BONUS_MAX = 0.9


HOMELESS_DEATH_RATE = 0.00025

# same as STARVATION_HAB_MODIFIER
HOMELESS_HAB_MODIFIER = 0.5


# 0 - 1
DEFAULT_HAB_RATING = 0.5
DEFAULT_MET_RATING = 0.5


# Habitability ratings lower than this require population to live in enclosed
# domes.
# 
# This functions as a minimum for such things as food production rates and
# health rating of population, but expenses generally increase all the way
# down to zero habitability (housing metal requirement, food metal requirement,
# etc.)
DOME_CUTOFF = 0.4


INIT_POPULATION = 1000.0
INIT_METAL = 1000.0
INIT_FOOD = 1000.0
INIT_RESEARCH = 0.0

# This is a multiplier. 1.0 means only the bare needed housing
INIT_HOUSING = 1.2

debug("""
DEFAULTS:
r: %F
population: %F
habitability: %F
metal: %F
research: %F
END DEFAULTS
""", 
POPULATION_GROWTH, INIT_POPULATION, DEFAULT_HAB_RATING, DEFAULT_MET_RATING, \
INIT_RESEARCH)


DEFAULT_GOALS = {}
DEFAULT_GOALS['housing'] = 0.20
DEFAULT_GOALS['mining'] = 0.20
DEFAULT_GOALS['food'] = 0.20
DEFAULT_GOALS['ships'] = 0.20
DEFAULT_GOALS['troops'] = 0.01
DEFAULT_GOALS['research'] = 0.08
DEFAULT_GOALS['health'] = 0.02
DEFAULT_GOALS['police'] = 0.02
DEFAULT_GOALS['military'] = 0.01
DEFAULT_GOALS['infrastructure'] = 0.04
DEFAULT_GOALS['entertainment'] = 0.01
DEFAULT_GOALS['unemployment'] = 0.01

debug("""
DEFAULT_GOALS:
housing:        %(housing)F
mining:         %(mining)F
food:           %(food)F
ships:          %(ships)F
troops:         %(troops)F
research:       %(research)F

health:         %(health)F
police:         %(police)F
military:       %(military)F
infrastructure: %(infrastructure)F
entertainment:  %(entertainment)F
unemployment:   %(unemployment)F
END DEFAULT GOALS
""", DEFAULT_GOALS)

# sanity check on default goals, check that they add to 1.0
assert(abs(sum(DEFAULT_GOALS.itervalues()) - 1.0) < E)
for x in DEFAULT_GOALS.itervalues():
    assert(x >= 0)

DEFAULT_EMPLOYMENT = {}

for key, value in DEFAULT_GOALS.iteritems():
    DEFAULT_EMPLOYMENT[key] = int(round(value * INIT_POPULATION))

# Invariant: floor(population) == sum(employment.values())
# employment.values() are all integers

# This next part fudges the values a bit in case of rounding errors
# if there are too few employed people, it adds them to unemployed
# if there are too many, it just picks people to get rid of
temp = 0
for key, value in DEFAULT_EMPLOYMENT.iteritems():
    if value < 0:
        DEFAULT_EMPLOYMENT[key] = 0
        value = 0
    temp = temp + value

diff = floor(INIT_POPULATION) - temp

if diff != 0:
    warning("\nDEFAULT_EMPLOYMENT has rounding errors.\n")

if diff > 0:
    DEFAULT_EMPLOYMENT['unemployment'] += diff
elif diff < 0:
    for key in DEFAULT_EMPLOYMENT:
        if DEFAULT_EMPLOYMENT[key] > 0:
            DEFAULT_EMPLOYMENT[key] = DEFAULT_EMPLOYMENT[key] - \
                                min(DEFAULT_EMPLOYMENT[key], -1 * diff)
            diff = diff + min(DEFAULT_EMPLOYMENT[key], -1 * diff)
            if diff == 0:
                break
# else diff == 0, nothing to do

del temp
del diff

debug("""
DEFAULT_EMPLOYMENT:
housing:        %(housing)s people
mining:         %(mining)s people
food:           %(food)s people
ships:          %(ships)s people
troops:         %(troops)s people
research:       %(research)s people

health:         %(health)s people
police:         %(police)s people
military:       %(military)s people
infrastructure: %(infrastructure)s people
entertainment:  %(entertainment)s people
unemployment:   %(unemployment)s people
END DEFAULT_EMPLOYMENT
""", DEFAULT_EMPLOYMENT)

assert(sum(DEFAULT_EMPLOYMENT.itervalues()) == int(INIT_POPULATION))
for x in DEFAULT_EMPLOYMENT.itervalues():
    assert(x > 0)


KEY_LIST = list(DEFAULT_EMPLOYMENT.iterkeys())

